package countPool

import (
	"fmt"
	"gitee.com/kingzyt/common/log"
)

type CountPool struct {
	name        string
	pool        chan byte
	warningLine int
	warningSum  int // 一定条数输出warning，避免集中输出warning，而进一步造成卡顿
}

// 因为单个goroutine会占用5k的空间，goroutine是数量是一个很影响内存占用的指标
/* i5,4核3.6GHz下
50000左右比较合适，
win7下测试，
10000是一个会造成处理速度偏慢的数量在3.3GHz4Core的主机上
100000会造成处理卡顿，有大量goroutine生成，容易发生goroutine耗尽但执行中的goroutine还没有来得及完成
*/
// 在i7的8核3.6GHz上，250000是一个总体可以接受的数字
const default_max_parallel_msg_proc_num = 50000

const Reverse_proxy_max_client_link_count = 100000

// 每N次超过warningLine输出一条log，10000在4核下比较适合
const default_warning_line_interval = 10000

// 一般从总pool里面限制goroutine数量
var GlobalGoroutinePool = NewCountPool("globalGoroutinePool", default_max_parallel_msg_proc_num, -1)

var GlobalTcpPool = NewCountPool("globalTcpPool", Reverse_proxy_max_client_link_count, -1)

const default_warning_line_percent float32 = 0.1

func NewCountPool(name string, poolSize int, warningLine int) *CountPool {
	if poolSize <= 0 {
		panic(fmt.Errorf("%s: poolSize[%d] is <= 0", name, poolSize))
	}

	if warningLine < 0 || warningLine > poolSize {
		warningLine = int(default_warning_line_percent * float32(poolSize))
	}

	rlt := &CountPool{
		name:        name,
		pool:        make(chan byte, poolSize),
		warningLine: warningLine,
		warningSum:  0,
	}
	for i := 0; i < poolSize; i++ {
		rlt.pool <- 1
	}
	return rlt
}

func (self *CountPool) GetOne() {
	// 这里仅仅是一个近似的检查，不用考虑线程安全
	if len(self.pool) < self.warningLine {
		if self.warningSum > default_warning_line_interval {
			self.warningSum = 0
			log.Warn(self.name, "pool is near empty, now count:%d, warningLine:%d, maybe block", len(self.pool), self.warningLine)
		}
		self.warningSum++
	}

	<-self.pool
}

func (self *CountPool) ReturnOne() {
	self.pool <- 1
}
